home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 2
/
Aminet AMIGA CDROM (1994)(Walnut Creek)[Feb 1994][W.O. 44790-1].iso
/
Aminet
/
mus
/
play
/
MP132src.lha
/
dssplay.asm
< prev
next >
Wrap
Assembly Source File
|
1992-09-14
|
20KB
|
720 lines
* MultiPlayer
* Copyright (C) 1992 Bryan Ford
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* See Player.doc for info on contacting the author.
*
* Note: This playroutine was not originally written by me. In general
* these playroutines are public domain, so I am bringing the versions
* modified for MultiPlayer under the General Public License. In the
* few cases of already-copyrighted playroutines, the above copyright
* notice applies only to the parts of the file written by me.
*
* $Id: dssplay.asm,v 4.1 92/07/12 10:40:43 BAF Exp $
*
include "player.i"
code text
xref modmem,dmawait
xdef dssstart
dssstart:
plstartret .gmod
cnop 0,4
dc.l gmod_Hook
.gmod
gmodnop
gmodbra InitPlay ; StartMusic
gmodbra RemovePlayer ; StopMusic
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop
gmodnop ; GetFrequency
gmodnop ; TimerTick
lea name(a4),a0 ; GetMakerName
move.l a0,d0
rts
;**************************************************************************
;*
;* DSS MODULE PLAY ROUTINE
;* -----------------------
;*
;* If you wish to use some DSS Tracker Modules into your own programs,
;* you can read the following listing...
;*
;* This file contains the needed functions for playing a DSS Module.
;* You have to allocate, to load and to free the memory (CHIP) yourself.
;*
;* >Once the Module is loaded in CHIP memory:
;*
;* -Set the [ SongPointer ] pointer (at the end of this file) with the
;* Module's address.
;* -Call the [ InitPlay() ] function.
;*
;* >To stop the Module, you just have to call the [ RemovePlayer() ]
;* function.
;*
;* This program has been writen for the Aztec C 3.6 assembler.
;* It can be easily adapted to another assembler.
;*
;**************************************************************************
;----- Amiga function ------
_LVOOpenResource EQU -498
_LVOAddICRVector EQU -6
_LVORemICRVector EQU -12
;------- ExecBase ----
SysBase EQU 4
PAL EQU 50
eb_PowerSupplyFreq EQU 531
;------- CIAA --------
CIAAPRA EQU $bfe001
CIABTALO EQU $bfd400
CIABTAHI EQU $bfd500
CIABICR EQU $bfdd00
CIABCRA EQU $bfde00
CIABTBLO EQU $bfd600
CIABTBHI EQU $bfd700
CIABCRB EQU $bfdf00
;------ Song ----------
sng_Tempo EQU 8
sng_Instr0 EQU 10
sng_Len EQU 1436
sng_Seq EQU 1438
sng_Data EQU 1566
;------ InstrData -----
MAXINSTR EQU 30
SIZEOF_insdt EQU 46
instr_Name EQU 0
instr_Start EQU 30
instr_Len EQU 34
instr_RStart EQU 36
instr_RLen EQU 40
instr_Vol EQU 42
instr_Freq EQU 44
;------- AudioData -
SIZEOF_ad EQU 24
ad_SampPer EQU 0
ad_Effet EQU 2
ad_Info EQU 3
ad_Volume EQU 4
ad_SmpAdr EQU 6
ad_SmpLen EQU 10
ad_RepAdr EQU 12
ad_RepLen EQU 16
ad_ArpPer EQU 18
ad_DMABit EQU 20
ad_PitchPer EQU 22
;------- AudioChips -------
DMACON EQU $dff096
DMASET EQU $8000
AUD0LCH EQU $dff0a0
AUD1LCH EQU $dff0b0
AUD2LCH EQU $dff0c0
AUD3LCH EQU $dff0d0
AUDxLEN EQU $4
AUDxPER EQU $6
AUDxVOL EQU $8
AUDxDAT EQU $a
SIZEOF_AUD EQU $10
;------ Block ---------
NEXTTRACK EQU 4
NEXTLINE EQU 16
BLOCKSIZE EQU 1024
MAXTRACK EQU 4
;------- Notes -------
DO2 EQU 1712
SI5 EQU 113
STOP EQU $7ff
;------- Effects -----
MASK_EFF EQU 7
MASK_VAL EQU $f
ARPEGGIO EQU 0
PITCHUP EQU 1
PITCHDOWN EQU 2
VOLUME EQU 3
MASTERVOL EQU 4
TEMPO EQU 5
JUMP EQU 6
FILTER EQU 7
MAX_VOL EQU 64
BREAK EQU $ff
;------------------ functions to call -----------------
; Timer interruption installation and Player initialization routines
; Return 0 (zero) if successful.
; Return 1 if the installation is not possible.
InitPlay:
lea clrstart,a0
moveq #(clrend-clrstart)/2-1,d0
.clr
clr.w (a0)+
dbra d0,.clr
movem.l d1-d2/a0-a3/a6,-(sp)
move.l SysBase,a6
lea CiabName,a1
moveq #0,d0
jsr _LVOOpenResource(a6)
move.l d0,CiabBase
beq.s InitPlayError
cmp.b #PAL,eb_PowerSupplyFreq(a6)
beq.s initsong
move.w #2,IsNTSC
initsong:
bsr InitSampleAdr
bsr InitSamples
bsr InitInterrupt
tst.l d0
beq EndInitPlay
InitPlayError:
moveq #1,d0
EndInitPlay:
movem.l (sp)+,d1-d2/a0-a3/a6
rts
; Stop to play the module
RemovePlayer:
movem.l d0-d1/a0-a1/a6,-(sp)
bsr DisablePlayer
move.l CiabBase,a6
lea TimerInt,a1
moveq #1,d0
jsr _LVORemICRVector(a6)
bclr #1,CIAAPRA
movem.l (sp)+,d0-d1/a0-a1/a6
rts
;-------------- internal functions -----------------
InitInterrupt:
bsr EnablePlayer
move.l CiabBase,a6
lea TimerInt,a1
moveq #1,d0
jsr _LVOAddICRVector(a6)
tst.l d0
bne.s InitInterruptEnd
move.b CIABCRB,d0
and.b #%10000000,d0
or.b #1,d0
move.b d0,CIABCRB
move.b #$82,CIABICR
lea TimerTable,a0
move.w IsNTSC,d0
move.b 1(a0,d0),CIABTBLO
move.b 0(a0,d0),CIABTBHI
moveq #0,d0
InitInterruptEnd:
rts
InitSampleAdr:
move.l modmem,a1
lea sng_Len(a1),a0
move.w (a0)+,d0 ; d0 = songlen
subq.w #1,d0
moveq #0,d1
move.l d1,d2
SeekLastBlockLoop:
move.b (a0)+,d2
cmp.b d2,d1
bhi.s NotLastBlock
move.b d2,d1
NotLastBlock:
dbra d0,SeekLastBlockLoop
addq.w #1,d1
moveq #10,d0
lsl.l d0,d1 ; d1 = block size
lea sng_Data(a1),a0
add.l d1,a0 ; a0 -> first sample
lea sng_Instr0(a1),a2 ; a2 -> first instrument
lea SampleAdrTable,a3
moveq #MAXINSTR,d0
InitAdrLoop:
moveq #0,d1
move.w instr_Len(a2),d1 ; len ?
beq.s InitNextAdr
InitThisAdr:
move.l a0,(a3)
moveq #0,d2
cmp.w #1,instr_RLen(a2) ; rlen
beq.s GetSampleSize
move.w instr_RLen(a2),d2
add.l d2,d1
GetSampleSize:
add.l d1,d1
bclr #0,instr_Start+3(a2) ; align instr_Start on a word
add.l instr_Start(a2),d1 ; Start
add.l d1,a0 ; a0 -> nextsample
InitNextAdr:
addq.l #4,a3
add.l #SIZEOF_insdt,a2
dbra d0,InitAdrLoop
rts
InitSamples:
lea SampleAdrTable,a0
moveq #MAXINSTR,d0
InitSamplesLoop:
move.l (a0)+,d1
beq.s InitSamplesLoopEnd
move.l d1,a1
moveq #3,d2
Clear4Bytes:
clr.b (a1)+
dbra d2,Clear4Bytes
InitSamplesLoopEnd:
dbra d0,InitSamplesLoop
rts
DisablePlayer:
clr.w AUD0LCH+AUDxVOL
clr.w AUD1LCH+AUDxVOL
clr.w AUD2LCH+AUDxVOL
clr.w AUD3LCH+AUDxVOL
move.w #$0f,DMACON
rts
EnablePlayer:
clr.w AUD0LCH+AUDxVOL
clr.w AUD1LCH+AUDxVOL
clr.w AUD2LCH+AUDxVOL
clr.w AUD3LCH+AUDxVOL
rts
TimerIntRoutine:
movem.l d1-d7/a0-a6,-(sp)
bsr.s PlayRoutine
movem.l (sp)+,d1-d7/a0-a6
moveq #0,d0
rts
PlayRoutine:
move.l modmem,a6
move.w 8(a6),d0
addq.w #1,PlayTimer
cmp.w PlayTimer,d0 ; tempo == playtimer ?
bne.s PlayEffects ; no, play effects
clr.w PlayTimer ; yes, reset timer to zero
bra PlaySound ; play note
PlayEffects:
lea ChannelData0,a0
lea AUD0LCH,a1
moveq #MAXTRACK-1,d3 ; 4 tracks
PlayEffLoop:
move.w (a0),d0
and.w #$7ff,d0
cmp.w #STOP,d0 ; note == STOP ?
beq.s PlayEffLoopEnd
tst.b ad_Info(a0) ; effect value == 0 ?
beq.s PlayEffLoopEnd
bsr.s MakeEffects
PlayEffLoopEnd:
add.l #SIZEOF_ad,a0 ; a0 -> next channeldata
add.w #SIZEOF_AUD,a1 ; a1 -> next audio register
dbra d3,PlayEffLoop
rts
MakeEffects:
move.b ad_Effet(a0),d0
beq.s EffArpeggio
cmp.b #PITCHUP,d0
beq.s EffPitchUp
cmp.b #PITCHDOWN,d0
beq.s EffPitchDown
rts
EffArpeggio:
moveq #0,d0
move.w PlayTimer,d0
cmp.w #1,d0
beq.s EffArpOne
cmp.w #2,d0
beq.s EffArpTwo
cmp.w #3,d0
beq.s EffArpThree
cmp.w #4,d0
beq.s EffArpTwo
cmp.w #5,d0
beq.s EffArpOne
rts
EffArpOne:
move.b ad_Info(a0),d0
lsr.b #4,d0 ; d0 = high nibble value
bra.s EffArpSeek
EffArpTwo:
move.b ad_Info(a0),d0
and.b #MASK_VAL,d0 ; d0 = low nibble value
bra.s EffArpSeek
EffArpThree:
move.w ad_ArpPer(a0),d2 ; d2 = normal period
bra.s EffArpFound
EffArpSeek:
add.w d0,d0 ; d0 = offset notetable
move.w ad_ArpPer(a0),d1 ; d1 = normal period
lea NoteTable,a2
EffArpLoop:
move.w 0(a2,d0.w),d2 ; d2 = new period
cmp.w (a2)+,d1 ; (a2) == normal period
bne.s EffArpLoop
EffArpFound:
move.w d2,AUDxPER(a1)
rts
EffPitchUp:
moveq #0,d0
move.b ad_Info(a0),d0 ; d0 = effect value
sub.w d0,ad_PitchPer(a0)
cmp.w #SI5,ad_PitchPer(a0) ; less than lowest period ?
bpl.s EffPitchOK
move.w #SI5,ad_PitchPer(a0)
bra.s EffPitchOK
EffPitchDown:
moveq #0,d0
move.b ad_Info(a0),d0
add.w d0,ad_PitchPer(a0)
cmp.w #DO2,ad_PitchPer(a0) ; more than highest period ?
bmi.s EffPitchOK
move.w #DO2,ad_PitchPer(a0)
EffPitchOK:
move.w ad_PitchPer(a0),AUDxPER(a1)
rts
PlaySound:
lea sng_Data(a6),a0
lea sng_Seq(a6),a1
move.w CurrentPos,d0
move.w d0,NewPosJump
moveq #0,d1
move.b 0(a1,d0.w),d1 ; d1 = block number
moveq #10,d0
lsl.l d0,d1
add.l OffsetBlock,d1 ; d1 = offset into block data
clr.w AudioDMA
lea AUD0LCH,a3
lea ChannelData0,a4
moveq #MAXTRACK-1,d7 ; 4 tracks
PlayLoop:
bsr PlayInstr
add.w #SIZEOF_AUD,a3
add.l #SIZEOF_ad,a4
dbra d7,PlayLoop
move.w AudioDMA,d0 ; start audio DMA
or.w #DMASET,d0
move.w d0,DMACON
move.b CIABCRA,d1 ; wait loop
move.b d1,d0
and.b #%11000000,d0
or.b #%00001000,d0
move.b d0,CIABCRA
move.b #$2f,CIABTALO
move.b #1,CIABTAHI
PlayDelay1:
btst.b #0,CIABCRA
bne.s PlayDelay1
move.b d1,CIABCRA
move.b #%00000001,CIABICR
lea ChannelData0,a0 ; set new value into audio registers
lea AUD0LCH,a1
moveq #MAXTRACK-1,d0
SetNewValue:
move.l ad_RepAdr(a0),(a1)
move.w ad_RepLen(a0),AUDxLEN(a1)
add.l #SIZEOF_ad,a0
add.w #SIZEOF_AUD,a1
dbra d0,SetNewValue
cmp.l #BLOCKSIZE-NEXTLINE,OffsetBlock ; end of block ?
beq.s ChangePosition
add.l #NEXTLINE,OffsetBlock ; modif. offsetblock
tst.w BreakStatus ; jump or break ?
beq.s PlaySoundEnd
clr.w BreakStatus
ChangePosition:
clr.l OffsetBlock ; offset block = 0
move.w NewPosJump,CurrentPos
addq.w #1,CurrentPos ; new position
move.w sng_Len(a6),d0
move.w CurrentPos,d1
cmp.w d0,d1 ; end of song ?
bne.s PlaySoundEnd
clr.w CurrentPos ; position = 0
PlaySoundEnd:
rts
PlayInstr:
lea sng_Instr0(a6),a2
move.l 0(a0,d1.l),ad_SampPer(a4)
addq.l #NEXTTRACK,d1
moveq #0,d0
move.b ad_SampPer(a4),d0
lsr.b #3,d0 ; d0 = instrument number
tst.b d0 ; d0 == 0 ?
beq.s NoSampleChange
lea SampleAdrTable,a5
subq.b #1,d0
move.l d0,d3
lsl.w #2,d0 ; d0 = SampleAdrTable offset
mulu #SIZEOF_insdt,d3
add.l #instr_Start,d3
add.l d3,a2 ; a2 -> Start InstrData
move.l 0(a5,d0.w),d4
add.l (a2)+,d4 ; Start
move.l d4,ad_SmpAdr(a4)
beq.s NoSampleChange
move.w (a2)+,ad_SmpLen(a4) ; Len
move.l (a2)+,d5 ; RStart
move.w (a2)+,d2 ; RLen
bne.s SetRepeat
moveq #1,d2
moveq #0,d5
SetRepeat:
move.w d2,ad_RepLen(a4)
add.l ad_SmpAdr(a4),d5
move.l d5,ad_RepAdr(a4)
move.w (a2),ad_Volume(a4) ; Volume
NoSampleChange:
move.w ad_SampPer(a4),d6
and.w #$7ff,d6 ; note == 0 ?
beq.s TestEffects
move.w d6,ad_ArpPer(a4)
move.w ad_DMABit(a4),d0
move.w d0,DMACON ; cut DMA audio for this track
move.b CIABCRA,d2 ; wait loop
move.b d2,d3
and.b #%11000000,d3
or.b #%00001000,d3
move.b d3,CIABCRA
move.b #$2f,CIABTALO
move.b #1,CIABTAHI
PlayDelay2:
btst.b #0,CIABCRA
bne.s PlayDelay2
move.b d2,CIABCRA
move.b #%00000001,CIABICR
cmp.w #STOP,d6 ; note == 'OFF' ?
bne.s SetPlayRegs
clr.w AUDxVOL(a3) ; set audio volume to 0
or.w d0,AudioDMA
rts
SetPlayRegs:
move.l ad_SmpAdr(a4),(a3) ; sample address == NULL ?
beq.s TestEffects
move.w ad_SmpLen(a4),AUDxLEN(a3)
move.w d6,AUDxPER(a3)
or.w d0,AudioDMA
move.w d6,ad_PitchPer(a4)
TestEffects:
move.b ad_Effet(a4),d0 ; d0 = effect
bsr.s EffVolume
tst.b d0
beq.s TestEffectsEnd
cmp.b #FILTER,d0
beq EffFilter
cmp.b #MASTERVOL,d0
beq.s EffMaster
cmp.b #TEMPO,d0
beq.s EffSpeed
cmp.b #JUMP,d0
beq.s EffJump
TestEffectsEnd:
rts
EffVolume: ; modify volume
cmp.w #VOLUME,d0
bne.s UseInstrVol
moveq #0,d2
move.b ad_Info(a4),d2 ; d0 = new volume
bra.s SetInstrVol
UseInstrVol:
tst.w d6
beq.s EffVolumeEnd
move.w ad_Volume(a4),d2
SetInstrVol:
sub.w MasterVolume,d2 ; new volume - master >= 0
bge.s SetVolumeReg
moveq #0,d2 ; new volume = 0
SetVolumeReg:
move.w d2,AUDxVOL(a3) ; new volume into audio reg
EffVolumeEnd:
rts
EffMaster: ; modify master volume
moveq #MAX_VOL,d2
move.b ad_Info(a4),d0
sub.b d0,d2
blt.s EffMasterEnd
move.b d2,MasterVolume+1
EffMasterEnd:
rts
EffSpeed: ; modify tempo
move.b ad_Info(a4),d0
beq.s EffSpeedEnd
clr.w PlayTimer
move.b d0,sng_Tempo+1(a6)
EffSpeedEnd:
rts
EffJump: ; jump or break
move.w #1,BreakStatus
move.b ad_Info(a4),d0
cmp.b #BREAK,d0
beq.s EffBreak
subq.b #2,d0
ext.w d0
move.w d0,NewPosJump
rts
EffBreak:
move.w CurrentPos,NewPosJump
rts
EffFilter: ; filter on/off
move.b ad_Info(a4),d0
bne.s SetFilter
bset #1,CIAAPRA
rts
SetFilter:
bclr #1,CIAAPRA
rts
data __MERGED
CiabBase: dc.l 0
IsNTSC: dc.w 0
CiabName: dc.b 'ciab.resource',0
TimerIntName: dc.b 'DSS Tracker Player',0
cnop 0,2
TimerInt:
dc.l 0 ; Interrupt.is_Node.ln_Succ
dc.l 0 ; Interrupt.is_Node.ln_Pred
dc.b 2 ; Interrupt.is_Node.ln_Type = NT_INTERRUPT
dc.b -10 ; Interrupt.is_Node.ln_Pri
dc.l TimerIntName ; Interrupt.is_Node.ln_Name
dc.l 0 ; Interrupt.is_Data
dc.l TimerIntRoutine ; Interrupt.is_Code
clrstart
PlayOn: dc.w 0
PlayTimer: dc.w 0
CurrentPos: dc.w 0
OffsetBlock: dc.l 0
AudioDMA: dc.w 0
MasterVolume: dc.w 0
BreakStatus: dc.w 0
NewPosJump: dc.w 0
clrend
ChannelData0:
dc.w 0 ; Period 0
dc.w 0 ; Sample+Info 2
dc.w 0 ; Volume 4
dc.l 0 ; Sample address 6
dc.w 0 ; Sample length 10
dc.l 0 ; Repeat address 12
dc.w 0 ; Repeat length 16
dc.w 0 ; Shazam period 18
dc.w 1 ; DMA bit 20
dc.w 0 ; Pitch period 22
ChannelData1:
ds.w 10
dc.w 2
dc.w 0
ChannelData2:
ds.w 10
dc.w 4
dc.w 0
ChannelData3:
ds.w 10
dc.w 8
dc.w 0
dc.w 1712
NoteTable:
dc.w 1712,1616,1524,1440,1356,1280,1208,1140,1076,1016,960,906
dc.w 856,808,762,720,678,640,604,570,538,508,480,453
dc.w 428,404,381,360,339,320,302,285,269,254,240,226
dc.w 214,202,190,180,170,160,151,143,135,127,120,113
dc.w 113,113,113,113,113,113,113,113,113,113,113,113
dc.w 113,113,113,113,113,113,113,113,113,113,113,113
dc.w 113,113,113,113,113,113
TimerTable: dc.w 14187,14318
SampleAdrTable: ds.l 31
name dc.b "Digital Sound Studio",0
end